package com.yonyou.ucf.mdf.app.isvdxq.utils;

import com.google.gson.Gson;
import org.apache.commons.lang3.StringUtils;

import javax.validation.constraints.NotNull;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.List;
import java.util.Random;

/**
 * 使用说明
 *  String r1 = Base64Util.ToBase64("asdfasdf",3);
 *  System.out.println(r1);
 *  String r2 = Base64Util.Base64ToString(r1,3);
 *  System.out.println(r2);
 */
public final class Base64Util {
    private static final String dateString = MyTool.GenerateTime("HHmmssSSS");
    private static final Random random = new Random(Integer.parseInt(dateString));
    // 随机字符长度
    public static final int RandomPrefixStrLength = 6;
    public static final String RandomStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    private static String GetRandomStr(String randomStr, int randomPrefixStrLength) throws InterruptedException {
        // ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=
        StringBuilder result = new StringBuilder();

        for (int i = 0; i < randomPrefixStrLength; i++) {
            int randomInt = random.nextInt(randomStr.length());
            char randomChar = randomStr.charAt(randomInt);
            result.append(randomChar);
        }

        Thread.sleep(1); // 休眠,以使随机数不重叠.

        return result.toString();
    }

    /**
     * 普通 字符串 转换为 base64 字符串
     */
    public static String ToBase64(@NotNull String str, int randomPrefixStrLength) {
        if (StringUtils.isBlank(str)) {
            return "";
        }

        try {
            String randomPrefixStr = GetRandomStr(RandomStr, randomPrefixStrLength);
            byte[] buffer = str.getBytes("utf-8");
            String base64Str = Base64.getMimeEncoder().encodeToString(buffer);
            base64Str = randomPrefixStrLength == 0 ? base64Str : InsertRandomStrToBase64Str(base64Str);

            return String.format("%s%s", randomPrefixStr, base64Str);
        } catch (RuntimeException | InterruptedException | UnsupportedEncodingException ex) {
            System.out.println("Base64Utility.ToBase64: " + ex.getMessage());
        }

        return "";
    }

    /**
     * base64 字符串 转换为 普通 字符串
     */
    public static String Base64ToString(@NotNull String base64Str, int randomPrefixStrLength) {
        if (StringUtils.isBlank(base64Str)) {
            return "";
        }
        String result = base64Str.trim();
        try {
            base64Str = base64Str.trim();
            String input = base64Str.substring(randomPrefixStrLength);
            input = randomPrefixStrLength == 0 ? input : RemoveBase64StrRandomStr(input);
            byte[] buffer = Base64.getDecoder().decode(input);

            result = new String(buffer, "utf-8");
        } catch (RuntimeException | UnsupportedEncodingException ex) {
            System.out.println("Base64Utility.Base64ToString:" + ex.getMessage());
        }

        return result;
    }

    public static class PwdDic {
        private String version;
        private List<PwdDicItem> item;

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }

        public List<PwdDicItem> getItem() {
            return item;
        }

        public void setItem(List<PwdDicItem> item) {
            this.item = item;
        }
    }

    public static class PwdDicItem {
        private int index;
        private int randomIndex;

        public int getIndex() {
            return index;
        }

        public void setIndex(int index) {
            this.index = index;
        }

        public int getRandomIndex() {
            return randomIndex;
        }

        public void setRandomIndex(int randomIndex) {
            this.randomIndex = randomIndex;
        }
    }

    // 100 以内字典
    public static final String dicString = "{\"version\":\"3\", \"item\":[{\"index\":99,\"randomIndex\":96}," +
            "{\"index\":52," +
            "\"randomIndex\":48},{\"index\":32,\"randomIndex\":24},{\"index\":22,\"randomIndex\":12},{\"index\":5," +
            "\"randomIndex\":2}]}";
    // 这里的 RandomIndex 要比 Index 小，而且Index 和 RandomIndex 所有的Value都是唯一的，不能重复。
    // 由于这里开源，所以这个字典需要自行定义。

    private static String InsertRandomStrToBase64Str(String base64Str) {
        String strResult = base64Str;
        PwdDic dic = new Gson().fromJson(dicString, PwdDic.class);
        for (PwdDicItem item : dic.getItem()) {
            if (item.getIndex() < base64Str.length()) {
                char randomChar = base64Str.charAt(item.getRandomIndex());
                strResult = MyTool.insertCharAt(strResult, item.getIndex(), randomChar);
            }
        }

        return strResult;
    }

    private static String RemoveBase64StrRandomStr(String input) {
        String strResult = input;
        PwdDic dic = new Gson().fromJson(dicString, PwdDic.class);
        List<PwdDicItem> items = dic.getItem();
        items.sort((PwdDicItem o1, PwdDicItem o2) -> {
            int id1 = o1.getIndex();
            int id2 = o2.getIndex();
            return id1 - id2;
        });
        for (PwdDicItem item : items) {
            if (item.getIndex() < strResult.length()) {
                strResult = MyTool.removeCharAt(strResult, item.getIndex());
            }
        }

        return strResult;
    }
}
